package main

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/binary"
	"fmt"
	"log"
	"net"
	"os"
	"time"
)

// Cabinet结构定义
type Cabinet struct {
	ID         string
	Name       string
	Devices    []DeviceSlave
	CommonAddr byte // 储能柜公共地址
}

// 修改创建设备数据ASDU函数
func (s *IEC104Slave) createDeviceDataASDU(dev DeviceSlave, cabinetAddr byte) *ASDU {
	// 根据设备类型创建不同的数据
	var typeID byte
	var data []byte

	switch dev.Type {
	case PCS:
		typeID = 0x09 // 测量值,标度化值
		data = make([]byte, 4)
		binary.LittleEndian.PutUint16(data[0:2], 22000) // 示例电压值
		binary.LittleEndian.PutUint16(data[2:4], 10000) // 示例电流值
	case BMS:
		typeID = 0x0D // 测量值,归一化值
		data = make([]byte, 6)
		binary.LittleEndian.PutUint16(data[0:2], 3600)  // 示例SOC
		binary.LittleEndian.PutUint16(data[2:4], 2500)  // 示例电压
		binary.LittleEndian.PutUint16(data[4:6], 45000) // 示例温度
	}

	return &ASDU{
		TypeID:     typeID,
		Variable:   0x01,
		Cause:      0x03,
		CommonAddr: cabinetAddr, // 使用储能柜地址
		InfoObj:    append([]byte{byte(dev.Address & 0xFF), byte(dev.Address >> 8)}, data...),
	}
}

// 修改主函数初始化
func main() {
	// 使用TLS初始化从站
	slave, err := NewIEC104Slave("2404",
		"server.crt",
		"server.key",
		"ca.crt")
	if err != nil {
		log.Fatal("创建从站失败:", err)
	}

	slave.siteAddr = 1 // 站点地址=1

	// 初始化储能柜(地址从2开始)
	slave.cabinets = []Cabinet{
		{
			ID:         "CAB001",
			Name:       "1号储能柜",
			CommonAddr: 2,
			Devices: []DeviceSlave{
				{ID: "PCS001", Type: PCS, Address: 0x1000},
				{ID: "BMS001", Type: BMS, Address: 0x2000},
			},
		},
		{
			ID:         "CAB002",
			Name:       "2号储能柜",
			CommonAddr: 3,
			Devices: []DeviceSlave{
				{ID: "PCS002", Type: PCS, Address: 0x1000},
				{ID: "BMS002", Type: BMS, Address: 0x2000},
			},
		},
	}

	go slave.Start()
	<-make(chan struct{})
}

// 修改NewIEC104Slave函数，添加TLS配置参数
func NewIEC104Slave(port string, certFile, keyFile, caFile string) (*IEC104Slave, error) {
	// 加载证书和私钥
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return nil, fmt.Errorf("加载证书失败: %v", err)
	}

	// 加载CA证书
	caCert, err := os.ReadFile(caFile)
	if err != nil {
		return nil, fmt.Errorf("加载CA证书失败: %v", err)
	}
	caCertPool := x509.NewCertPool()
	caCertPool.AppendCertsFromPEM(caCert)

	// 配置TLS
	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
		ClientCAs:    caCertPool,
		ClientAuth:   tls.RequireAndVerifyClientCert,
		MinVersion:   tls.VersionTLS13, // 强制使用TLS 1.3
	}

	// 创建TLS监听器
	listener, err := tls.Listen("tcp", ":"+port, tlsConfig)
	if err != nil {
		return nil, fmt.Errorf("创建TLS监听器失败: %v", err)
	}

	return &IEC104Slave{
		conn:     listener,
		stopChan: make(chan struct{}),
	}, nil
}

// 启动从站服务
func (s *IEC104Slave) Start() {
	log.Println("IEC104从站服务启动，监听端口:", s.conn.Addr().String())

	for {
		select {
		case <-s.stopChan:
			return
		default:
			conn, err := s.conn.Accept()
			if err != nil {
				log.Println("接受连接错误:", err)
				continue
			}

			go s.handleConnection(conn)
		}
	}
}

// 处理客户端连接
func (s *IEC104Slave) handleConnection(conn net.Conn) {
	defer conn.Close()

	log.Println("客户端连接:", conn.RemoteAddr())

	buf := make([]byte, 1024)
	for {
		n, err := conn.Read(buf)
		if err != nil {
			log.Println("读取数据错误:", err)
			return
		}

		frame, err := s.parseFrame(buf[:n])
		if err != nil {
			log.Println("解析帧错误:", err)
			continue
		}

		switch frame.Control[0] & 0x03 {
		case 0x01: // I格式帧(信息传输)
			s.handleIFrame(conn, frame)
		case 0x03: // U格式帧(控制功能)
			s.handleUFrame(conn, frame)
		}
	}
}

// 发送ASDU
// 在IEC104Slave结构体中添加序列号控制字段
type IEC104Slave struct {
	conn      net.Listener
	cabinets  []Cabinet
	stopChan  chan struct{}
	siteAddr  byte
	sendSeqNo uint16 // 发送序列号
	recvSeqNo uint16 // 接收序列号
}

// 修改sendASDU函数，添加序列号控制
func (s *IEC104Slave) sendASDU(conn net.Conn, asdu *ASDU) {
	frame := &IEC104Frame{
		StartByte: 0x68,
		Control:   s.buildControlField(true), // 构建控制域
		ASDU:      asdu.Bytes(),
	}
	conn.Write(frame.Bytes())
	s.sendSeqNo++ // 发送成功后序列号递增
}

// 添加控制域构建函数
func (s *IEC104Slave) buildControlField(isSend bool) [4]byte {
	var control [4]byte
	if isSend {
		// I格式帧控制域
		control[0] = byte(s.sendSeqNo << 1)
		control[1] = byte(s.sendSeqNo >> 7)
		control[2] = byte(s.recvSeqNo << 1)
		control[3] = byte(s.recvSeqNo >> 7)
	}
	return control
}

// 修改handleIFrame函数，处理接收序列号
func (s *IEC104Slave) handleIFrame(conn net.Conn, frame *IEC104Frame) {
	// 检查帧类型
	switch frame.Control[0] & 0x03 {
	case 0x01: // I格式帧(信息传输)
		// 更新接收序列号
		s.recvSeqNo = uint16(frame.Control[0])>>1 | uint16(frame.Control[1])<<7

		asdu := parseASDU(frame.ASDU)
		switch asdu.TypeID {
		case 0x64: // 总召唤
			s.handleGeneralInterrogation(conn, asdu)
		case 0x65: // 时钟同步
			s.handleClockSync(conn, asdu)
		}

		// 当接收序列号达到一定数量时发送S帧确认
		if s.recvSeqNo%8 == 0 { // 每接收8个I帧发送一次S帧确认
			s.sendSFrame(conn)
		}

	case 0x02: // S格式帧(接收确认)
		// 更新发送窗口
		recvSeqNo := uint16(frame.Control[2])>>1 | uint16(frame.Control[3])<<7
		if recvSeqNo > s.sendSeqNo {
			s.sendSeqNo = recvSeqNo
		}
	}
}

// 新增发送S帧函数
func (s *IEC104Slave) sendSFrame(conn net.Conn) {
	frame := &IEC104Frame{
		StartByte: 0x68,
		Length:    0x04,
		Control: [4]byte{
			0x01,                   // 控制域字节1(S帧标志)
			0x00,                   // 控制域字节2
			byte(s.recvSeqNo << 1), // 控制域字节3(接收序列号低7位)
			byte(s.recvSeqNo >> 7), // 控制域字节4(接收序列号高1位)
		},
	}
	conn.Write(frame.Bytes())
}

// 修改handleGeneralInterrogation函数，添加分帧发送逻辑
func (s *IEC104Slave) handleGeneralInterrogation(conn net.Conn, asdu *ASDU) {
	// ... 确认帧发送代码保持不变 ...

	// 分帧发送设备数据
	const maxPerFrame = 10 // 每帧最大信息对象数
	var objCount int

	for _, cabinet := range s.cabinets {
		for _, dev := range cabinet.Devices {
			dataASDU := s.createDeviceDataASDU(dev, cabinet.CommonAddr)
			s.sendASDU(conn, dataASDU)
			objCount++

			// 达到最大对象数时等待确认
			if objCount >= maxPerFrame {
				s.waitForConfirmation(conn)
				objCount = 0
			}
		}
	}

	// ... 结束帧发送代码保持不变 ...
}

// 添加等待确认函数
func (s *IEC104Slave) waitForConfirmation(conn net.Conn) {
	// 实现等待接收方确认的逻辑
	// 这里简化处理，实际应根据协议实现超时重发等机制
}

// 停止从站服务
func (s *IEC104Slave) Stop() {
	close(s.stopChan)
	s.conn.Close()
	log.Println("IEC104从站服务已停止")
}

type Device struct {
	ID      string
	Type    DeviceType
	Address uint16
}

// 主函数

// IEC104帧结构
type IEC104Frame struct {
	StartByte byte
	Length    byte
	Control   [4]byte
	ASDU      []byte
}

// ASDU结构
type ASDU struct {
	TypeID     byte
	Variable   byte
	Cause      byte
	CommonAddr byte
	InfoObj    []byte
}

// 设备类型枚举
type DeviceType int

const (
	PCS = iota
	BMS
	METER
	ENVIRONMENT
	AIR_CONDITIONER
	WATER_SENSOR
)

// 设备信息
type DeviceSlave struct {
	ID      string
	Type    DeviceType
	Address uint16
}

// 解析IEC104帧
func (s *IEC104Slave) parseFrame(data []byte) (*IEC104Frame, error) {
	if len(data) < 6 {
		return nil, fmt.Errorf("帧长度不足")
	}

	// 检查起始字节
	if data[0] != 0x68 {
		return nil, fmt.Errorf("无效的起始字节")
	}

	length := data[1]
	if int(length)+2 != len(data) {
		return nil, fmt.Errorf("长度字段与实际长度不匹配")
	}

	frame := &IEC104Frame{
		StartByte: data[0],
		Length:    data[1],
		ASDU:      data[6:],
	}

	// 复制控制域
	copy(frame.Control[:], data[2:6])

	return frame, nil
}

// 解析ASDU
func parseASDU(data []byte) *ASDU {
	if len(data) < 6 {
		return nil
	}

	return &ASDU{
		TypeID:     data[0],
		Variable:   data[1],
		Cause:      data[2],
		CommonAddr: data[3],
		InfoObj:    data[4:],
	}
}

// ASDU转换为字节
func (a *ASDU) Bytes() []byte {
	data := make([]byte, 4+len(a.InfoObj))
	data[0] = a.TypeID
	data[1] = a.Variable
	data[2] = a.Cause
	data[3] = a.CommonAddr
	copy(data[4:], a.InfoObj)
	return data
}

// 处理U格式帧
func (s *IEC104Slave) handleUFrame(conn net.Conn, frame *IEC104Frame) {
	// 检查U格式帧类型
	switch frame.Control[0] & 0xFC {
	case 0x04: // STARTDT激活
		// 发送确认
		confirmFrame := &IEC104Frame{
			StartByte: 0x68,
			Length:    0x04,
			Control:   [4]byte{0x07, 0x00, 0x00, 0x00},
		}
		conn.Write(confirmFrame.Bytes())
	case 0x08: // STARTDT确认
		// 不做处理
	case 0x10: // STOPDT激活
		// 发送确认
		confirmFrame := &IEC104Frame{
			StartByte: 0x68,
			Length:    0x04,
			Control:   [4]byte{0x23, 0x00, 0x00, 0x00},
		}
		conn.Write(confirmFrame.Bytes())
	case 0x20: // STOPDT确认
		// 不做处理
	case 0x40: // TESTFR激活
		// 发送确认
		confirmFrame := &IEC104Frame{
			StartByte: 0x68,
			Length:    0x04,
			Control:   [4]byte{0x83, 0x00, 0x00, 0x00},
		}
		conn.Write(confirmFrame.Bytes())
	case 0x80: // TESTFR确认
		// 不做处理
	}
}

// 处理时钟同步
func (s *IEC104Slave) handleClockSync(conn net.Conn, asdu *ASDU) {
	// 发送确认
	confirmASDU := &ASDU{
		TypeID:     asdu.TypeID,
		Variable:   asdu.Variable,
		Cause:      0x07, // 激活确认
		CommonAddr: asdu.CommonAddr,
	}
	s.sendASDU(conn, confirmASDU)

	// 发送时钟同步响应
	now := time.Now()
	timeData := make([]byte, 7)
	timeData[0] = byte(now.Year() % 100) // 年(后两位)
	timeData[1] = byte(now.Month())      // 月
	timeData[2] = byte(now.Day())        // 日
	timeData[3] = byte(now.Hour())       // 时
	timeData[4] = byte(now.Minute())     // 分
	timeData[5] = byte(now.Second())     // 秒
	timeData[6] = 0x00                   // 毫秒(简单处理)

	respASDU := &ASDU{
		TypeID:     asdu.TypeID,
		Variable:   asdu.Variable,
		Cause:      0x0A, // 激活结束
		CommonAddr: asdu.CommonAddr,
		InfoObj:    append([]byte{byte(asdu.InfoObj[0]), byte(asdu.InfoObj[1])}, timeData...),
	}
	s.sendASDU(conn, respASDU)
}

// IEC104帧转换为字节
func (f *IEC104Frame) Bytes() []byte {
	data := make([]byte, 6+len(f.ASDU))
	data[0] = f.StartByte
	data[1] = f.Length
	copy(data[2:6], f.Control[:])
	copy(data[6:], f.ASDU)
	return data
}
